Модуль:Типовая статья о человеке

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Документация
local moduleDate = require('Module:Wikidata/date')
local moduleWikidata = require('Module:Wikidata')
local p = {}
local refs = {}
local refcount = 0

local function renderStatement(frame, args)
	return moduleWikidata.formatProperty(frame:newChild{args = args})
end

-- "cite web"-based reference formatter
local function renderReference(frame, entity, reference)
    local url = nil
    local title = nil
    local lang = nil
    local date = nil
    local publisher = nil
    local archiveurl = nil
    local archivedate = nil
    local accessdate = nil
	
	if reference.snaks.P854 ~= nil then
		url = reference.snaks.P854[1].datavalue.value
	end
	
	if reference.snaks.P1476 ~= nil then
		title = reference.snaks.P1476[1].datavalue.value.text
		lang = reference.snaks.P1476[1].datavalue.value.language
	end
	
	if reference.snaks.P1065 ~= nil then
		archiveurl = reference.snaks.P1065[1].datavalue.value
	end
	
	if reference.snaks.P2960 ~= nil then
		archivedate = reference.snaks.P2960[1].datavalue.value.time
	end
	
	if url == nil and archiveurl ~= nil then
		url = archiveurl
		archiveurl = nil
		archivedate = nil
	end
	
	if archiveurl ~= nil and archivedate == nil then
		archivedate = ' '
	end
	
	if title == nil and url ~= nil then
		title = url
	end
	
	local ref = ''
	
	if url == nil then
		ref = 'Unsupported reference (no URL provided)'
	else
		if reference.snaks.P813 ~= nil then
			accessdate = string.sub(reference.snaks.P813[1].datavalue.value.time, 2, 11)
		end
		
		if reference.snaks.P577 ~= nil then
			date = string.sub(reference.snaks.P577[1].datavalue.value.time, 2, 5)
		end
		
		if reference.snaks.P123 ~= nil then
			publisher = mw.wikibase.label(reference.snaks.P123[1].datavalue.value.id)
		end
		
		ref = '{{cite web'
		ref = ref .. '|url=' .. url
		ref = ref .. '|title=' .. title
		ref = ref .. '|lang=' .. lang
		if date ~= nil then ref = ref .. '|date=' .. date end
		if publisher ~= nil then ref = ref .. '|publisher=' .. publisher end
		if accessdate ~= nil then ref = ref .. '|accessdate=' .. accessdate end
		if archiveurl ~= nil then ref = ref .. '|archiveurl=' .. archiveurl .. '|archivedate=' .. archivedate end
		ref = ref .. '}}'
	end
	
	hash = mw.hash.hashValue('md5', ref)
	local refidx = refs[hash]
	if refidx ~= nil then
		return frame:extensionTag('ref', '', {name ='ref' .. refs[hash]})
	else
		refcount = refcount + 1
		refs[hash] = refcount
		return frame:extensionTag('ref', ref, {name ='ref' .. refcount})
	end
end

local function formatSchool( name )
	name = mw.ustring.gsub(name, "Старш", "старш")
	name = mw.ustring.gsub(name, "ая ", "ую ")
	name = mw.ustring.gsub(name, "[Шш]кола", "школу")
	name = mw.ustring.gsub(name, "[Аа]кадемия", "академию")
	return name
end

local function formatName( frame, name )
	return frame:preprocess("{{safesubst:#ifexpr: {{safesubst:str find|{{safesubst:До символа|" .. name .. "|(}}|,}} = -1 " ..
	"|{{safesubst:#invoke:string2|bs|" .. name .. "|(|1}}" ..
	"|{{safesubst:#invoke:string2|as|{{safesubst:#invoke:string2|bs|" .. name .. "|(|1}}|,}} {{safesubst:#if:1|{{safesubst:#invoke:string2|bs|{{safesubst:#invoke:string2|bs|" .. name .. "|(|1}}|,|1}}}}" ..
	"}}")
end

local function formatCitizenship( claims, is_female )
	if claims == nil then return end
	local qid = claims[1].mainsnak.datavalue.value.id
	local tbl = {
		Q17='японск',
		Q30='американск',
		Q159='российск',
		Q183='немецк',
		Q7318='немецк',
		Q41304='немецк',
		Q43287='немецк',
	}
	local word = tbl[qid]
	if word == nil then return end
	word = word .. (is_female and 'ая' or 'ий')
	return '[[' .. mw.wikibase.sitelink( qid ) .. '|' .. word .. ']]'
end

-- plain replacement routine
local function replace(text, from, to)
	local pattern = from:gsub('[%^%$%(%)%%%.%[%]%*%+%-%?]','%%%1')
	local replacement = to:gsub('[%^%$%(%)%%%.%[%]%*%+%-%?]','%%%1')
	return text:gsub(pattern, replacement)
end

local function cleanup( text )
	-- simplify names for reused refs, remove names for single-used refs
	refs = {}
	for s in text:gsub('<ref name=".-"','\0%0\0'):gsub('%z%z','\0 \0'):gmatch'%z<ref name="(.-)"%z' do
		refs[s] = (refs[s] or 0) + 1
	end
	
	refindex = 1
	for ref, count in pairs(refs) do
		if count == 1 then
			text = replace(text, ' name="' .. ref .. '"', '')
		else
			text = replace(text, ref, 'ref' .. refindex)
			refindex = refindex + 1
		end
	end
	
	-- move categories to bottom (for subst)
	cats = {}
	for s in text:gsub('%[%[Category:[^]]+%]%]','\0%0\0'):gsub('%z%z','\0 \0'):gmatch'%z%[%[Category:(.-)%]%]%z' do
		cats[s] = true
	end
	for s in text:gsub('%[%[Категория:[^]]+%]%]','\0%0\0'):gsub('%z%z','\0 \0'):gmatch'%z%[%[Категория:(.-)%]%]%z' do
		cats[s] = true
	end
	cats['Википедия:Статьи с источниками из Викиданных'] = nil  -- we don't need this category in substitution
	text = text:gsub('%[%[Category:[^]]+%]%]',''):gsub('%[%[Категория:[^]]+%]%]','') .. '\n\n'
	for cat, _ in pairs(cats) do
		text = text .. '[[Категория:' .. cat .. ']]\n'
	end
	
	text = text:gsub('<span style="display:none">\(.?<span class=".-</span>.?\)</span>', '')
	text = text:gsub('<span.->', '')
	text = text:gsub('</span>', '')
	text = text:gsub('(%d)]] год', '%1 год]]')
	text = text:gsub('\n\n\n+', '\n\n')
	text = text:gsub('<div style="display:none"></div>', '')
	-- text = text:gsub('<', '&lt;')
	return text
end

local function formatPreferredAwards( frame, entity )
	local r = '' 
	local awards = entity.claims.P166
	local lst = {}

	for k, v in pairs( awards ) do
		if v.rank == 'preferred' then
			local o = {}
			local qid = v.mainsnak.datavalue.value.id
			local sitelink = mw.wikibase.sitelink( qid )
			local label = mw.wikibase.label( qid )
			label = mw.ustring.gsub(label, "[Пп]ремия", "премии")
			label = mw.ustring.gsub(label, "[Нн]аграда", "награды")
			label = mw.ustring.gsub(label, "[Оо]рден", "ордена")
			label = mw.ustring.gsub(label, "[Мм]едаль", "медали")
			if sitelink ~= nil then
				o.link = '[[' .. sitelink .. '|' .. label .. ']]'
			else
				o.link = label
			end
			o.refs = v.references
			table.insert(lst, o)
		end
	end

	local function formatRefs(references)
		local out = ''
		if references then
			for _, reference in pairs(references) do
				out = out .. renderReference(frame, entity, reference)
			end
		end
		return out
	end

	for i = 1, #lst do
		r = r .. lst[i].link .. formatRefs(lst[i].refs)
		if i < #lst - 1 then
			r = r .. ', '
		elseif i == #lst - 1 then
			r = r .. ' и '
		end
	end

	return r
end

local function hasPreferredAwards( entity )
	local awards = entity.claims.P166
	for k, v in pairs( awards ) do
		if v.rank == 'preferred' then
			return true
		end
	end
	return false
end

local function formatExtraSources( entity )
	for _, v in pairs( entity.claims.P973 ) do
		local r = ''
		local url = v.mainsnak.datavalue.value
		if url ~= nil then
			if v.qualifiers ~= nil and v.qualifiers.P1476 ~= nil then
				local title = v.qualifiers.P1476[1].datavalue.value.text
				local iso_code = nil
				local accessdate = nil
				local publisher = nil
	
				if v.qualifiers.P407 ~= nil then
					local lang_qid = v.qualifiers.P407[1].datavalue.value.id
					local lang_el = mw.wikibase.getEntity(lang_qid)
					if lang_el.claims.P218 ~= nil then
						iso_code = lang_el.claims.P218[1].mainsnak.datavalue.value
					end
				end
				
				if v.qualifiers.P813 ~= nil then
					accessdate = v.qualifiers.P813[1].datavalue.value.time
				end
				
				if v.qualifiers.P123 ~= nil then
					publisher = mw.wikibase.label(v.qualifiers.P123[1].datavalue.value.id)
				end
				
				r = r .. '* {{cite web|title=' .. title .. '|url=' .. url
				if iso_code ~= nil then r = r .. '|lang=' .. iso_code end
				if accessdate ~= nil then r = r .. '|accessdate=' .. accessdate end
				if publisher ~= nil then r = r .. '|publisher=' .. publisher end
				r = r .. '}}\n'
			end
		end
		return r
	end
end

local function formatAwards( frame, entity )
	local r = '\n\n' .. [[
== Награды и номинации ==
{| class="wikitable" style="font-size:90%"
|-
! scope="col" style="background:#B0C4DE" | Год
! scope="col" style="background:#B0C4DE" | Премия
! scope="col" style="background:#B0C4DE" | Работа
! scope="col" style="background:#B0C4DE" | Результат
! scope="col" style="background:#B0C4DE" | Примечание]]
	
	local awards = entity.claims.P166
	local nominations = entity.claims.P1411
	
	local lst = {}
	local nom = 'background:Gainsboro;" | Номинация'
	local win = 'background:Gold;" | Победа'
	
	local function fillAwards( from, to, isnom )
        if from == nil then return end
		for k, v in pairs( from ) do
		    local o = {}
		    o.name = mw.wikibase.renderSnak( v.mainsnak )
	        if v.qualifiers ~= nil and v.qualifiers.P585 ~= nil then
	        	o.when = frame:preprocess(string.format('{{год в кино|%s}}', mw.wikibase.renderSnak( v.qualifiers.P585[1] )))
	        	-- o.when = mw.wikibase.renderSnak( v.qualifiers.P585[1] )
	        end
	        if v.qualifiers ~= nil and v.qualifiers.P1686 ~= nil then
	        	o.forwhat = mw.wikibase.renderSnaks( v.qualifiers.P1686 )
	        end
	        
	        o.refs = v.references
	        o.isnom = isnom
	        table.insert(to, o)
		end
	end

	local function formatRefs(references)
		local out = ''
        if references then
			for _, reference in pairs(references) do
				out = out .. renderReference(frame, entity, reference)
			end
		end
		return out
	end
	
	fillAwards( awards, lst, false )
	fillAwards( nominations, lst, true )

	table.sort(lst, function (a, b)
      return a.when < b.when
    end)
    
    for i = 1, #lst do
	  r = r .. string.format('\n' .. [[|-
| %s
| %s
| %s
| style="text-align:center; %s
| %s]], lst[i].when or "", lst[i].name, lst[i].forwhat or "", (lst[i].isnom and nom or win), formatRefs(lst[i].refs))
	end
	
	r = r .. '\n|}\n'
	
	return r
end

local function top( frame, entity )
	local r = frame:preprocess('{{ {{{|safesubst:}}}ifsubst||{{Предупреждение в типовой статье|Типовая статья о человеке|' .. entity.id .. '}}\n}}')

	local surname = entity.claims.P734 ~= nil and mw.wikibase.sitelink( entity.claims.P734[1].mainsnak.datavalue.value.id )
	local name = entity.claims.P735 ~= nil and mw.wikibase.sitelink( entity.claims.P735[1].mainsnak.datavalue.value.id )
	if surname then
		if name then
			r = r .. frame:preprocess('{{имя+фамилия|'.. name .. '|' .. surname .. '}}\n')
		else
			r = r .. frame:preprocess('{{однофамильцы|' .. surname .. '}}\n')
		end
	end
	
	r = r .. frame:preprocess('{{персона|from=' .. entity.id .. '}}\n')
	
	local s = {}
	local is_female = (entity.claims.P21 ~= nil) and (entity.claims.P21[1].mainsnak.datavalue.value['numeric-id'] == 6581072)
	
	if is_female then
		s.was_born = 'родилась'
		s.His = 'Её'
		s.Was_member_of = 'Была участницей'
		s.Spouse = 'Муж'
		s.Died = 'Умерла'
		s.Buried = 'Похоронена'
		s.Awarded = 'обладательница '
		s.Finished = 'Закончила'
	else
		s.was_born = 'родился'
		s.His = 'Его'
		s.Was_member_of = 'Был участником'
		s.Spouse = 'Жена'
		s.Died = 'Умер'
		s.Buried = 'Похоронен'
		s.Awarded = 'обладатель '
		s.Finished = 'Закончил'
	end
	
	local name = formatName( frame, mw.title.getCurrentTitle().text )

    local birth_date = renderStatement(frame, {property='P569', ['value-module']='Wikidata/date', ['value-function']='formatBirthDate', from=entity.id})
    local birth_place = renderStatement(frame, {property='P19', preset='name', ['claim-module']='Wikidata/Places', ['claim-function']='formatPlaceWithQualifiers', from=entity.id})
	local basic_info = birth_date .. ', ' .. birth_place
	
	if entity.claims.P570 ~= nil then
    	local death_date = renderStatement(frame, {property='P570', ['value-module']='Wikidata/date', ['value-function']='formatDeathDate', from=entity.id})
    	local death_place = renderStatement(frame, {property='P20', preset='name', ['claim-module']='Wikidata/Places', ['claim-function']='formatPlaceWithQualifiers', from=entity.id})
		basic_info = basic_info .. ' — ' .. death_date .. ', ' .. death_place
	end
	
	if entity.claims.P1814 ~= nil then
		r = r .. frame:preprocess('{{нихонго-но-намаэ|\'\'\'' .. name .. '\'\'\'|{{safesubst:#property:P1814}}||4=' .. basic_info .. '}}')
	elseif entity.claims.P1559 ~= nil and entity.claims.P1559[1].mainsnak.datavalue.value.language ~= 'ru' then
		local orig_name_val = entity.claims.P1559[1].mainsnak.datavalue.value
		local orig_name = '{{lang-' .. orig_name_val.language .. '|' .. orig_name_val.text .. '}}'
		r = r .. frame:preprocess('\'\'\'' .. name .. '\'\'\' (' .. orig_name .. '; ' .. basic_info .. ')')
	else
		r = r .. frame:preprocess('\'\'\'' .. name .. '\'\'\' (' .. basic_info .. ')')
	end
	
	if entity.claims.P27 ~= nil then
		local occupation = renderStatement(frame, {property='P106', from=entity.id})
		local citizenship = formatCitizenship(entity.claims.P27, is_female)
		if citizenship ~= nil then
			r = r .. frame:preprocess(' — ' .. citizenship .. ' ' .. occupation)
		else
			r = r .. frame:preprocess(' — ' .. occupation .. ' ({{safesubst:#property:P27}})')
		end
	end
	
	if entity.claims.P166 ~= nil and hasPreferredAwards( entity ) then
		r = r .. frame:preprocess(', ' .. s.Awarded) .. formatPreferredAwards( frame, entity )
	end
	
	r = r .. '.'
	
	if entity.claims.P1875 ~= nil then
		r = r .. frame:preprocess(' Работает под эгидой агентства {{safesubst:#property:P1875}}.')
	end

	r = r .. '\n\n== Биография ==\n'

	r = r .. frame:preprocess(name .. ' ' .. s.was_born .. ' {{safesubst:#property:P569}} {{safesubst:wikidata/where|P19}}.')
	
	if entity.claims.P69 ~= nil then  -- учебное заведение
		local schools = entity.claims.P69
		r = r .. ' ' .. s.Finished .. ' ' .. formatSchool(mw.wikibase.label(schools[1].mainsnak.datavalue.value.id))
		
		if schools[1].qualifiers ~= nil then
			local at = schools[1].qualifiers.P582  -- дата окончания
			if at ~= nil and at[1].datavalue.value.precision == 9 then
				r = r .. ' в ' .. moduleDate.formatDate( {}, {}, at[1].datavalue.value ) .. ' году'
			end
		end
		r = r .. '.'
	end
	
	if entity.claims.P793 ~= nil then
		local stepping_out = nil
		local events = entity.claims.P793
		
		for k, v in pairs( events ) do
		    if v.mainsnak.datavalue.value['numeric-id'] == 22075993 and  -- сценический дебют
		       v.qualifiers.P585[1].datavalue.value.precision == 9 then
		    	stepping_out = 'в ' .. moduleDate.formatDate( {}, {}, v.qualifiers['P585'][1].datavalue.value ) .. ' году'
		    end
		end
		
		if stepping_out ~= nil then
			r = r .. frame:preprocess(' ' .. s.His .. ' актёрский дебют состоялся ' .. stepping_out .. '.')
		end
	end
	
	r = r .. '\n\n'

	if entity.claims.P108 ~= nil then
		local work_place = renderStatement(frame, {property='P108', preset='name', from=entity.id})
		r = r .. frame:preprocess('Место работы — ' .. work_place .. '.\n\n')  -- падеж, даты
	end

	if entity.claims.P463 ~= nil then
		local member_of = renderStatement(frame, {property='P463', from=entity.id})
		if #entity.claims.P463 == 1 then
			r = r .. frame:preprocess(s.Was_member_of .. ' организации ' .. member_of .. '.\n\n')
		else
			r = r .. frame:preprocess(s.Was_member_of .. ' организаций: ' .. member_of .. '.\n\n')
		end
	end

	if entity.claims.P26 ~= nil then
		local spouse = renderStatement(frame, {property='P26', from=entity.id})
		r = r .. frame:preprocess(s.Spouse .. ' — ' .. spouse .. '.\n\n')
	end

	if entity.claims.P570 ~= nil then  -- умер
		r = r .. frame:preprocess(s.Died .. ' {{safesubst:#property:P570}}')

		if entity.claims.P20 ~= nil then  -- где
			r = r .. frame:preprocess(' {{safesubst:wikidata/where|P20}}')
		end

		if entity.claims.P1196 ~= nil then  -- род смерти
			local death_cause = renderStatement(frame, {property='P1196', from=entity.id})
			r = r .. frame:preprocess(', род смерти — ' .. death_cause)
		end
		
		r = r .. '. '
	end

	if entity.claims.P119 ~= nil then  -- похоронен
		r = r .. frame:preprocess(s.Buried .. ' {{safesubst:wikidata/where|P119|P1791}}.\n')
	end
	
	if entity.claims.P166 ~= nil or entity.claims.P1411 ~= nil then
		r = r .. formatAwards( frame, entity )
	end
	
	return r
end

local function bottom( frame, entity )
	local r = ''

	r = r .. '\n== Примечания ==\n'
	r = r .. frame:preprocess('{{примечания|2}}\n')

	r = r .. '\n== Ссылки ==\n'
	if entity['claims']['P345'] ~= nil then
		r = r .. frame:preprocess('* {{imdb name|{{safesubst:str sub|{{safesubst:#property:P345}}|2|100}}}}\n')
	end
	if entity['claims']['P2013'] ~= nil then
		r = r .. frame:preprocess('* {{Facebook|{{safesubst:#property:P2013}}}}\n')
	end
	if entity['claims']['P973'] ~= nil then
		r = r .. frame:preprocess(formatExtraSources(entity))
	end
	r = r .. frame:preprocess('\n{{Внешние ссылки}}')
	return r
end

function p.render( frame )
	local entity = mw.wikibase.getEntity(frame.args.from)
	local r = top( frame, entity )
	
	if frame.args[1] ~= nil and #frame.args[1] > 0 then
		r = r .. '\n== ' .. frame.args[1] .. ' ==\n'
		r = r .. frame.args[2]
	end
	
	r = r .. bottom( frame, entity )
	return cleanup(r)
end

return p